﻿////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// <copyright>Copyright 2008-2011 Andreas Huber Doenni</copyright>
// Distributed under the Microsoft Public License (Ms-PL).
// See accompanying file License.txt or copy at http://mews.codeplex.com/license.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

namespace Mews.Net.Nntp.Cache
{
    using System;
    using System.Data;
    using System.Data.SqlServerCe;
    using System.Globalization;

    /// <summary>Represents the MetaData values stored in the database.</summary>
    internal sealed class MetaData : IDisposable
    {
        private const int ExpectedVersion = 0;

        private readonly SqlCeCommand command;
        private readonly SqlCeResultSet resultSet;

        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>See <see cref="IDisposable.Dispose"/>.</summary>
        public void Dispose()
        {
            this.resultSet.Dispose();
            this.command.Dispose();
        }

        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        internal MetaData(Database database)
        {
            using (var commandGuard = ScopeGuard.Create(this.command =
                new SqlCeCommand(MetaDataNames.Table, database.Connection) { CommandType = CommandType.TableDirect }))
            {
                try
                {
                    using (var resultSetGuard = ScopeGuard.Create(
                        this.resultSet = this.command.ExecuteResultSet(ResultSetOptions.Updatable)))
                    {
                        this.resultSet.Read();
                        commandGuard.Dismiss();
                        resultSetGuard.Dismiss();
                    }
                }
                catch (SqlCeException ex)
                {
                    ThrowIncompatibleCacheException(ex);
                }
            }
        }

        internal int InsertsAndDeletesSinceLastCompaction
        {
            get
            {
                return (int)this.resultSet[MetaDataNames.InsertsAndDeletesSinceLastCompactionColumn];
            }

            set
            {
                this.resultSet.SetValue(MetaDataNames.InsertsAndDeletesSinceLastCompactionColumn, value);
                this.resultSet.Update();
            }
        }

        internal void CheckVersion()
        {
            try
            {
                var actualVersion = (int)this.resultSet[MetaDataNames.VersionColumn];

                if (actualVersion != ExpectedVersion)
                {
                    throw new IncompatibleCacheException(string.Format(
                        CultureInfo.InvariantCulture,
                        "The actual version {0} does not match the expected version {1}.",
                        actualVersion,
                        ExpectedVersion));
                }
            }
            catch (IndexOutOfRangeException ex)
            {
                ThrowIncompatibleCacheException(ex);
            }
            catch (InvalidCastException ex)
            {
                ThrowIncompatibleCacheException(ex);
            }
        }

        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        private static void ThrowIncompatibleCacheException(Exception ex)
        {
            throw new IncompatibleCacheException("Unable to read the metadata table.", ex);
        }
    }
}
